home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-06-15 | 40.3 KB | 1,284 lines |
- /*
- * Copyright (c) 1990, 1991, 1992 Stanford University
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose is hereby granted without fee, provided
- * that (i) the above copyright notices and this permission notice appear in
- * all copies of the software and related documentation, and (ii) the name
- * Stanford may not be used in any advertising or publicity relating to
- * the software without the specific, prior written permission of
- * Stanford.
- *
- * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
- * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
- *
- * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
- * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
- * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
- * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
-
- /* $Header: /Source/Media/collab/VideoObject/RCS/NECDriver.c,v 0.32 93/02/07 13:02:29 drapeau Exp $ */
- /* $Log: NECDriver.c,v $
- * Revision 0.32 93/02/07 13:02:29 drapeau
- * Changed method in which driver waits for outstanding return codes. The
- * driver now tries to take into account multiple NEC drivers being called from
- * the same application. The old scheme did not work when doing dubbing operations
- * where two NEC's were involved.
- * This scheme has not been completely tested, and some errors may remain.
- *
- * Revision 0.31 92/10/01 14:26:13 drapeau
- * Fixed minor errors in NECSendCode() and NECReadOK() to improve response of
- * the NEC PC-VCR driver.
- * In NECSendCode(), added a test to check if the "CL" interrupt command was
- * sent, in addition to testing for the "CV" interrupt command being sent.
- * Also, added a diagnostic message to make debugging of the driver simpler.
- * In NECReadOK(), added code to consume leftover completion codes. This occurs
- * when a PlayFromTo() is sent with a non-blocking status (which tells
- * NECSendCode() not to wait for the completion message). If the NECStop()
- * function is called before the PlayFromTo completes, the Stop command
- * tells the deck to disregard any outstanding commands, in effect removing the
- * completion code from the NEC's output buffer. If, however, the PlayFromTo
- * manages to complete before the Stop function is called (or any function, for
- * that matter), the NEC will be left with a completion code waiting to be
- * consumed; it appears that even the "CV" and "CL" interrupt commands will not
- * wipe this completion code out of the NEC's output buffer.
- * So, NECReadOK() checks for this latter case, where an outstanding completion
- * code is read from the buffer when in fact the "command acknowledged" code was
- * expected.
- *
- * Revision 0.30 92/09/29 18:13:32 drapeau
- * Made several improvements to the driver and fixed a few errors.
- * The improvements have to do with improving the response time of the NEC when
- * performing the NECPlayFromTo() function. Before the improvements were made,
- * PlayFromTo() always blocked until the playback was completed. Now, the
- * playback begins and the function returns immediately, returning control to
- * the calling application. If a stop or pause message are sent before playback
- * is complete, the playback will quickly be interrupted by the new driver.
- * In addition, fixed an error in NECSendCode(): the function was checking the
- * string "command" to see if the command being sent was an interrupt command;
- * instead, NECSendCode() should have been checking the incoming "code" string
- * passed in as argument.
- *
- * Revision 0.29 92/09/28 12:39:09 drapeau
- * PlayFromTo() was modified to reflect the new semantics of the VideoObject
- * library.
- *
- * Revision 0.28 92/09/08 14:39:07 drapeau
- * Made several changes to account for limitations of the NEC PC-VCR. The code
- * to handle these limitations used to be in the vcrEdit application, but it
- * is more appropriate to handle the NEC-specific limitations here.
- * Specifically, the NEC PC-VCR cannot access the 1st 3 seconds of timecoded
- * tape, so searches to any address less than 3 seconds are now caught as
- * invalid in the NECSearch() function.
- * Also, the NEC cannot play a segment of video less than 3 seconds long, so
- * the PlayFromTo() function now catches this error and accommodates for the
- * problem by temporarily adjusting the endpoint of the video segment so that
- * the edit will last 3 seconds. It is still up to the author to modify the
- * edit length in the application's edit list (or whereever the edit length
- * is stored).
- *
- * Revision 0.27 92/09/01 17:04:52 drapeau
- * Fixed errors in calls to NECSetAudio(); it was being called with an extra
- * parameter; this was caught as a result of adding function prototypes to
- * all related files, for better ANSI compliance.
- * Fixed definition of NECSetAddressingMode() to comply with definition of
- * the generic VideoObject.
- * Added methods NECRecord() and NECRecordFromTo() in accordance with new
- * VideoObject methods.
- *
- * Revision 0.26 92/08/05 16:15:34 drapeau
- * Made several improvements to the CalcSpeed and PlayAtSpeedDir functions,
- * so they don't call the NEC too often. Since communications with the
- * NEC is slow, it is always to the advantage of the driver to avoid
- * sending commands and queries to the NEC. The new functions keep
- * some internal state about the NEC playback mode, in order to avoid
- * constant queries to the NEC.
- * Also, minor cosmetic changes to some diagnostic-printing calls.
- *
- * Revision 0.25 92/07/30 15:24:27 drapeau
- * Several changes:
- * * Renamed "VcrInsert()" and "VcrPlayTo()" to "NECInsert()" and
- * "NECPlayTo()".
- * * Removed all XView-specific code, to increase the portability of the driver.
- * * Re-formatted all function declarations to conform to ANSI function
- * prototype standards.
- * * Replaced hard-coded references to 30 frame-per-second frame rates with
- * new definition "FrameRate". All math is based on this definition now,
- * allowing the driver to be used in places where the frame rate is not
- * 30 fps.
- * * Improved diagnostic messages. Diagnostics now report the serial port
- * being used for the command when possible.
- *
- * Revision 0.24 92/06/16 23:45:33 drapeau
- * Changed the way asynchronous calls are handled, to avoid using XView-specific
- * code. This might need to be changed one more time, when the new
- * toolkit-independent asynchronous I/O scheme is implemented for all
- * appropriate drivers (including this one).
- *
- * Revision 0.23 92/01/03 16:49:33 drapeau
- * Changed occurrances of "NULL" in calls to Browse() to use "0" instead.
- * This is due to the ANSI definition of NULL as "(void*)0".
- *
- * Revision 0.22 91/09/30 17:04:40 lim
- * Implemented NECPing.
- *
- * Revision 0.21 91/08/28 14:10:29 lim
- * Changed use of Error to PlayerReturnError
- *
- * Revision 0.20 91/08/27 17:47:55 lim
- * Corrected calls to DisplayError(). Now there is a second
- * argument as well.
- *
- * Revision 0.19 91/08/24 17:49:43 lim
- * Implemented PrintDiagnostics.
- *
- * Revision 0.18 91/08/24 13:37:13 lim
- * 1. Updated to use status codes in new PlayerStatus.h
- * 2. Clear Marker() removed as part of video object.
- *
- * Revision 0.17 91/08/20 16:28:27 lim
- * Parameters for SetVideo : 0 - Video mute
- * 1 - Video on
- *
- * Revision 0.16 91/08/20 10:05:51 lim
- * A blocking segment play function is added which is used by the dubbing
- * application.
- *
- * Revision 0.15 91/08/17 20:36:56 lim
- * 1. Stop and Pause implemented with interrupt capability.
- * 2. Clear Marker implemented to do as specs in videoObj.h require.
- * 3. Audio fixed so that segment play reflects user's audio setting.
- * 4. Fixed QueryAudio and QueryVideo.
- *
- * Revision 0.14 91/08/15 12:51:13 lim
- * Changed interrupt command to use "CV" which clears buffer and is able to interrupt any command
- * currently being executed.
- *
- * Revision 0.13 91/08/12 13:14:17 lim
- * Removed Quit() call from CheckTape.
- *
- * Revision 0.12 91/08/08 16:17:44 lim
- * 1. Removed references to vcrEdit app, so as to be able to incorporate
- * into library.
- * 2. Added instance pointer, 'theObject' to all public calls.
- * 3. Added SetAddressingMode, which sets 'addMode' to 1 for indexing and
- * 0 for normal.
- * 4. Removed DisplaySpeed. Now PlayAtSpeedDir() uses framesPerSecond to
- * judge how to change speed.
- * 5. Added NECClient and now PlayFromTo() uses notify_set_input_func rather
- * than timers.
- * 6. ReadHeader() has second parameter, 'result' which allows result of
- * query to be passed back to the calling function even if it is not an
- * integer.
- *
- * Revision 0.11 91/07/20 11:38:22 lim
- * Changed NECPlayFromTo to fit function
- * prototype. The speed field does nothing in actuality, because
- * the NEC is unable to play edits at speeds other than 30 f/s.
- * NULL for startFrame in NECPlayFromTo now means resume play
- * and do not set counter. This used to be represented by -1.
- * Added NECCalcSpeed. Always returns 30.
- * All floats are changed to doubles.
- *
- * Revision 0.10 91/07/16 16:10:49 lim
- * Initial revision.
- * */
-
- #include "NECDriver.h"
-
- static char vcrrcsid[] = "$Header: /Source/Media/collab/VideoObject/RCS/NECDriver.c,v 0.32 93/02/07 13:02:29 drapeau Exp $";
-
- int addMode; /* Addressing mode : 1 = Index, 0 = Normal */
- int audioMuted; /* Whether audio has been muted or not for segment play.
- QueryAudio is unable to detect this condition. */
- int waitConsumeAO[2] = {0, 0}; /* Set to 1 when we do not wait to consume the AO after
- issuing a command. */
- static char diagMsg[128];
-
-
- /* Support routines. These implement the VCR functions */
-
-
- /* Check status of player. */
- int
- NECQueryStatus(VideoObject* theObject)
- {
- NECSendCode(theObject, "DS", 1);
- return(NECReadResponse(theObject, "DS"));
- } /* end function NECQueryStatus */
-
-
- /* Checks if a tape has been inserted into the deck.
- * If no tape, display message and checks again.
- * If the user does not want to insert a tape, the program quits.
- */
- void
- NECCheckTape(VideoObject* theObject)
- {
- int result;
- int choice;
-
- result = NECQueryStatus(theObject);
- if (result == PlayerNoMedium)
- {
- choice = DisplayChoice("Please insert a tape into the player.","",
- "OK", "No");
- if (choice)
- NECCheckTape(theObject);
- else
- return;
- }
- } /* end function NECCheckTape */
-
-
- /* Initializes the NEC to default settings */
- int
- NECSetDefaults(VideoObject* theObject,
- int audio,
- int addMode, /* unused */
- int addDisplay, /* unused */
- int addDisplayMode) /* unused */
- {
- NECPower(theObject, FeatureOn); /* Turn on player */
- NECStop(theObject);
- NECSetVideo(theObject, FeatureOn);
- NECScreenSelect(theObject, Green, BrightnessNormal);
- NECClearScreen(theObject);
- NECSetAudio(theObject, audio);
- NECCheckTape(theObject); /* Checks if tape has been inserted */
- return(PlayerOk);
- } /* end function NECSetDefaults */
-
-
-
- /* Convert address passed in (in terms of # of frames) into format used by player */
- void
- NECConvertAdd(int* start,
- int* startFrame,
- int* end,
- int* endFrame,
- int startAdd,
- int endAdd)
- {
- if (startAdd < 0)
- startAdd = -startAdd;
-
- *start = startAdd / FrameRate;
- *startFrame = startAdd % FrameRate;
-
- *end = endAdd / FrameRate;
- *endFrame = endAdd % FrameRate;
- return;
- } /* end function NECConvertAdd */
-
-
- /* Functions to send and read commands from NEC */
-
- /* Sends vcr code.
- * Reads CP or error message.
- * Checks if we are waiting for a status. If so, we return to calling function.
- * Otherwise, we read AO or error message.
- */
- int
- NECSendCode(VideoObject* theObject,
- char* code,
- int waitStatus)
- {
- char command[15];
- int w;
- int result;
- int whichPlayer = 0;
-
- if (strcmp(theObject->DevConfig->serialPort, "/dev/ttya") == 0) /* Determine which serial port is being used for... */
- whichPlayer = 0; /* ...this command */
- else
- whichPlayer = 1;
-
- if (waitConsumeAO[whichPlayer] != 0) /* Is the driver waiting to consume a completion code? */
- { /* Yes (this flag set only by the PlayFromTo method) */
- sprintf(diagMsg, "%s :\twaitConsumeAO flag was set; reading AO.\n",
- theObject->DevConfig->serialPort,
- w, code);
- PrintDiagnostics(diagMsg);
- if ((strcmp(code, "CV") != 0) && (strcmp(code, "CL") != 0)) /* Is the incoming command an interrupt? */
- NECReadOK(theObject, "AO", "SP"); /* No, normal command: read completion from last command */
- waitConsumeAO[whichPlayer] = 0;
- }
- strcpy(command,code);
- strcat(command,"\r");
- w = write(theObject->DevConfig->fd,command,strlen(command));
- sprintf(diagMsg, "%s :\tWrote %d bytes, code is ::%s::\n",
- theObject->DevConfig->serialPort,
- w, code);
- PrintDiagnostics(diagMsg);
-
- result = NECReadOK(theObject, "CP",code);
- if (result == PlayerReturnError)
- return result;
-
- if (waitStatus == 0) /* Should the function wait for an "AO"? */
- return (NECReadOK(theObject, "AO" , code)); /* Yes, block until it or an error condition is returned */
- else /* No, return immediately */
- return PlayerOk;
- } /* end function NECSendCode */
-
-
- /* Reads ack codes (CP or AO) from NEC.
- * If error, display error message.
- */
- int
- NECReadOK(VideoObject* theObject,
- char* okCode,
- char* currCom)
- {
- int i;
- int returnCode;
- char response[15];
-
- if ((i = read(theObject->DevConfig->fd, response, 15)) > 0)
- {
- response[i-1] = '\0';
-
- sprintf(diagMsg, "%s :\tRead %d bytes, response is ::%s::\n",
- theObject->DevConfig->serialPort,
- i, response);
- PrintDiagnostics(diagMsg);
-
- if (strncmp(response, "EE", 2) == 0)
- {
- sscanf(&response[2],"%d",&returnCode);
- NECErrorDecode(theObject, returnCode, currCom);
- return PlayerReturnError;
- }
- else if (strncmp(response, okCode, 2) == 0)
- return PlayerOk;
- else if ((strncmp(okCode, "CP", 2) == 0) && /* Check if the driver is expecting a "command accepted"... */
- (strncmp(response, "AO", 2) == 0)) /* ...code but the NEC returned a "command completed";... */
- { /* ...This indicates that the last command's completion... */
- NECReadOK(theObject, okCode, currCom); /* ...was not consumed until now. So, now that it is... */
- } /* ...consumed, the current "command accepted" code can... */
- } /* ... be consumed. */
- else
- return PlayerReturnError;
- } /* end function NECReadOK */
-
-
-
- /* Returns response (status or information) from NEC.
- * If error, display error message.
- */
- int
- NECReadResponse(VideoObject* theObject,
- char* currCom)
- {
- int i;
- int returnCode;
- char response[15];
-
- if ((i = read(theObject->DevConfig->fd, response, 15)) > 0)
- {
- response[i-1] = '\0';
-
- sprintf(diagMsg, "%s :\tRead %d bytes, response is ::%s::\n",
- theObject->DevConfig->serialPort,
- i, response);
- PrintDiagnostics(diagMsg);
- if (strncmp(response, "EE", 2) == 0) /* Error message */
- {
- sscanf(&response[2],"%d",&returnCode);
- NECErrorDecode(theObject, returnCode, currCom);
- return (PlayerReturnError);
- }
- else if (strncmp(response, "SS", 2) == 0) /* Status return */
- {
- sscanf(&response[2],"%d",&returnCode);
- switch (returnCode)
- {
- case 0:
- returnCode = PlayerNoMedium;
- break;
- case 1:
- returnCode = PlayerStop;
- break;
- case 2:
- returnCode = PlayerRecording;
- break;
- case 3:
- returnCode = PlayerRecordPause;
- break;
- case 4:
- returnCode = PlayerForwardFast;
- break;
- case 5:
- returnCode = NECHiSpeedSearch;
- break;
- case 6:
- returnCode = NECPictureSearch;
- break;
- case 7:
- returnCode = PlayerForwardPlay;
- break;
- case 9:
- returnCode = PlayerPause;
- break;
- case 10:
- returnCode = NECRPictureSearch;
- break;
- case 11:
- returnCode = NECRHiSpeedSearch;
- break;
- case 12:
- returnCode = PlayerReverseFast;
- break;
- case 13:
- returnCode = NECForwardIndexScanSearch;
- break;
- case 14:
- returnCode = NECIndexScan;
- break;
- case 15:
- returnCode = NECReverseIndexScanSearch;
- break;
- case 16:
- returnCode = NECSlow1_30;
- break;
- case 17:
- returnCode = NECSlow1_10;
- break;
- case 18:
- returnCode = NECSlow1_5;
- break;
- case 19:
- returnCode = NECInsertPause;
- break;
- case 20:
- returnCode = NECInsertPlay;
- break;
- case 21:
- returnCode = NECAudioDubPause;
- break;
- case 22:
- returnCode = NECAudioDubPlay;
- break;
- case 23:
- returnCode = NECAudioInsertPause;
- break;
- case 24:
- returnCode = NECAudioInsertPlay;
- break;
- default:
- returnCode = PlayerUnknownReturnCode;
- }
- }
- else if (strncmp(response, "PG", 2) == 0) /* Tape address */
- sscanf(&response[2],"%d",&returnCode);
- else if (strncmp(response, "PY", 2) == 0) /* Video signal info */
- returnCode = PlayerVideoSignalPresent;
- else if (strncmp(response, "PN", 2) == 0)
- returnCode = PlayerVideoSignalAbsent;
- else if (strncmp(response, "MONO", 4) == 0) /* Status returns that are not integers */
- returnCode = PlayerAudioMono;
- else if (strncmp(response, "STEREO", 6) == 0)
- returnCode = PlayerAudioStereo;
- else if (strncmp(response, "LINE-IN", 7) == 0)
- returnCode = PlayerLineInput;
- else if (strncmp(response, "TV-IN", 5) == 0)
- returnCode = PlayerTunerInput;
- else if (strncmp(response, "L-OUT", 5) == 0)
- returnCode = PlayerAudioLeft;
- else if (strncmp(response, "R-OUT", 5) == 0)
- returnCode = PlayerAudioRight;
- else if (strncmp(response, "RL-OUT", 6) == 0)
- returnCode = PlayerAudioStereo;
- else if (strncmp(response, "NORMAL", 6) == 0)
- returnCode = PlayerAudioStereo;
- else if (strncmp(response, "PICTURE", 7) == 0)
- returnCode = PlayerVideoSignalPresent;
- else if (strncmp(response, "NO-PICTURE", 10) == 0)
- returnCode = PlayerVideoSignalAbsent;
- else if (strncmp(response, "STANDARD", 8) == 0)
- returnCode = PlayerSPMode;
- else if (strncmp(response, "EXTENDED", 8) == 0)
- returnCode = PlayerEPMode;
-
- NECReadOK(theObject, "AO", currCom); /* Except for error messages, all other ...
- ... responses have AO ack sent at the end. */
- return (returnCode);
-
- }
- } /* end function NECReadResponse */
-
-
-
- /* Player functions */
-
-
- /* Reads tape header.
- * If no tape, display message and tries to read header again.
- * If the user does not want to insert a tape, the program quits.
- * Otherwise, stores tape header info into currTape and resets counter.
- */
- int
- NECReadHeader(VideoObject* theObject,
- char* header)
- {
- char response[15];
- int result;
- int i;
-
- NECCheckTape(theObject); /* Checks that a tape exists */
-
- NECSendCode(theObject, "HR", 1);
- if ((i = read(theObject->DevConfig->fd, response, 15)) > 0)
- {
- response[i-1] = '\0';
-
- sprintf(diagMsg, "%s :\tRead %d bytes, response is ::%s::\n",
- theObject->DevConfig->serialPort,
- i, response);
- PrintDiagnostics(diagMsg);
- if (strncmp(response, "EE", 2) == 0) /* Error message */
- {
- sscanf(&response[2],"%d",&result);
- NECErrorDecode(theObject, result, "HR");
- return PlayerReturnError;
- }
- else if (strncmp(response, "HG", 2) == 0)
- strncpy(header, &response[2], 4);
- }
- NECReadOK(theObject, "AO", "HG");
- NECSendCode(theObject, "CR", 0); /* Counter reset */
- return PlayerOk;
-
- } /* end function NECReadHeader */
-
-
- int
- NECStop(VideoObject* theObject)
- {
- NECSendCode(theObject, "CV", 0); /* Clears all commands */
- NECSendCode(theObject, "CL", 0); /* Clears command buffer */
- return (NECSendCode(theObject, "ST", 0));
- } /* end function NECStop */
-
-
- /* Ejects the tape.
- * First checks if it is ok to eject the tape. We cannot do it while recording.
- * If it is recording, we display error message.
- * If not, we eject and try to read header of new tape.
- */
- int
- NECEject(VideoObject* theObject)
- {
- int result;
-
- result = NECQueryStatus(theObject);
-
- if ((result == PlayerRecording) || /* Not valid when in recording */
- (result == PlayerRecordPause))
- {
- DisplayError("Eject cannot be executed when recording", " ");
- return PlayerReturnError;
- }
- else
- {
- NECSendCode(theObject, "EJ", 0);
- NECCheckTape(theObject);
- return PlayerOk;
- }
- } /* end function NECEject */
-
-
- /* Pauses the tape.
- * First checks if it is ok to pause the tape. We can only do it while in record/playback.
- * If neither, we display error message.
- */
- int
- NECStill(VideoObject* theObject)
- {
- int result;
-
- NECSendCode(theObject, "CV", 0); /* Clears all commands */
- result = NECQueryStatus(theObject);
-
- switch (result)
- {
- case PlayerForwardPlay:
- case PlayerPause:
- case PlayerRecording:
- case PlayerRecordPause:
- return (NECSendCode(theObject, "PS",0));
- default:
- NECSendCode(theObject, "PL", 0);
- return (NECSendCode(theObject, "PS",0));
- }
-
- } /* end function NECStill */
-
-
- int
- NECPlay(VideoObject* theObject)
- {
- return (NECSendCode(theObject, "PL",0));
- } /* end function NECPlay */
-
-
-
- /* Search to address.
- * Mutes video and audio before search, and resets it after search.
- */
- void
- NECSearch(VideoObject* theObject,
- int address,
- int frame)
- {
- int searchAddress = 0;
- char command[10];
-
- searchAddress = (address * FrameRate) + frame; /* Calculate the requested search address */
- if (searchAddress < (3 * FrameRate)) /* Was the requested address illegal? (the NEC cannot... */
- { /* ...search to a position before 3 seconds into the... */
- DisplayError("The NEC PC-VCR cannot access the 1st 3 seconds", /* ...coded portion of the tape) If so, print an error... */
- "of its tape. Please try somewhere later in the tape."); /* ...and return without doing the search. */
- return;
- }
-
- NECSendCode(theObject, "VM1", 0); /* Mute video and audio before searching */
- NECSendCode(theObject, "AM1", 0);
-
- sprintf(command, "JP%d:%d", address, frame);
- NECSendCode(theObject, command, 0);
-
- NECSendCode(theObject, "VM0", 0); /* Reset video and audio after searching */
- NECSendCode(theObject, "AM0", 0);
- return;
- } /* end function NECSearch */
-
-
- /* Plays a segment of video.
- * Searches to start address if we don't want to start from current position.
- * Plays to end address.
- * A timer is set to receive the AO ack after correct amount of time, so as...
- * ... not to hold up the application.
- */
- int
- NECPlayFromTo(VideoObject* theObject,
- int startAdd,
- int endAdd,
- int speedInFrames) /* Not used, NEC is unable to play edits ... */
- { /* ... at speeds other than 1x speed */
- char command[10];
- int from;
- int fromFrame;
- int to;
- int toFrame;
- int initialAudioSetting;
- int whichPlayer = 0;
-
- if (strcmp(theObject->DevConfig->serialPort, "/dev/ttya") == 0) /* Determine which serial port is being used for... */
- whichPlayer = 0; /* ...this command */
- else
- whichPlayer = 1;
-
- if (addMode) /* Is address mode index mode? */
- {
- addMode = 0; /* Yes, set address mode to frame mode */
- return (NECSearchIndex(theObject, startAdd, endAdd));
- }
-
- if ((startAdd != 0) && (endAdd != 0) && (startAdd != endAdd) && /* If edit is a "play from start to end" edit, then... */
- ((endAdd - startAdd) < (3 * FrameRate))) /* ...is the requested edit less than 3 seconds long? */
- { /* Yes, report the error and adjust so something is played */
- DisplayError("The NEC PC-VCR cannot play edits less than 3 seconds.",
- "Please make necessary adjustments in the future.");
- endAdd = (startAdd + (3 * FrameRate)); /* Make the requested segment 3 seconds long */
- }
-
- NECConvertAdd(&from, &fromFrame,
- &to, &toFrame, startAdd, endAdd);
- if (startAdd == endAdd) /* Case a: Search to start address and still */
- {
- NECSearch(theObject, from, fromFrame);
- return(PlayerOk); /* NECSearch should really return a status value,... */
- } /* ...but it doesn't, so this function will return something */
-
- if ((startAdd > 0) && (endAdd == 0)) /* Case b: Search to start addr. and still (blocking search) */
- { /* Search to start address without losing audio setting. */
- initialAudioSetting = NECQueryAudio(theObject); /* Query current audio setting */
- NECSearch(theObject, from, fromFrame); /* Do the search */
- if (!audioMuted) /* Restore Audio if necessary */
- {
- switch (initialAudioSetting)
- {
- case PlayerAudioLeft:
- NECSetAudio(theObject, 1);
- break;
- case PlayerAudioRight:
- NECSetAudio(theObject, 2);
- break;
- case PlayerAudioStereo:
- NECSetAudio(theObject, 3);
- break;
- }
- }
- return(PlayerOk);
- }
-
- if ((startAdd == 0) && (endAdd > 0)) /* Case c: play from current position (no search) until... */
- { /* ...endAdd is reached, at speed "speedInFrames" */
- sprintf(command, "SP%d:%d", to, toFrame); /* Play to end address. */
- NECSendCode(theObject, command, 1); /* Send the command but do not block waiting for completion */
- waitConsumeAO[whichPlayer] = 1; /* Set flag telling NECSendCode to wait for completion... */
- if (audioMuted) /* ...of this command the next time it is called */
- audioMuted = 0;
- }
- if ((startAdd != 0) && (endAdd != 0) && (startAdd < endAdd)) /* Case d: play from startAdd to endAdd in... */
- { /* ...speed "speedInFrames" */
- NECSearch(theObject, from, fromFrame); /* Search to start address */
- sprintf(command, "SP%d:%d", to, toFrame); /* Play to end address. */
- NECSendCode(theObject, command, 1);
- if (audioMuted)
- audioMuted = 0;
- }
- return PlayerOk;
- } /* end function NECPlayFromTo */
-
-
-
- int
- NECStep(VideoObject* theObject,
- enum Direction direction)
- {
- int result;
-
- if (direction == Reverse) /* Reverse step is not available with the NEC */
- return PlayerOk;
-
- result = NECQueryStatus(theObject);
-
- if (result == PlayerPause) /* Valid only when in playback pause */
- {
- return (NECSendCode(theObject, "FS", 0));
- }
- else
- {
- DisplayError("Player must be in playback pause mode first", " ");
- return PlayerReturnError;
- }
- } /* end function NECStep */
-
-
- int
- NECFastForward(VideoObject* theObject)
- {
- int mode;
- int result;
- char command[3];
-
- if (addMode) /* Addressing mode is index */
- {
- addMode = 0;
- return (NECScanIndex(theObject, Forward));
- }
-
- result = NECQueryStatus(theObject);
-
- if ((result == PlayerForwardPlay) || (result == PlayerPause)) /* If in playback mode, we scan forward */
- mode = 1;
- else if ((result != PlayerRecording) &&
- (result != PlayerRecordPause)) /* Otherwise, we fast forward - Not valid if recording */
- mode = 0;
- else
- DisplayError("Fast forward not valid when recording", " ");
-
- sprintf(command, "FF%d", mode);
- return (NECSendCode(theObject, command, 0));
-
- } /* end function NECFastForward */
-
-
- int
- NECReverse(VideoObject* theObject)
- {
- int mode;
- char command[3];
- int result;
-
- if (addMode) /* Addressing mode is index */
- {
- addMode = 0;
- return (NECScanIndex(theObject, Reverse));
- }
-
- result = NECQueryStatus(theObject);
-
- if ((result == PlayerForwardPlay) || (result == PlayerPause)) /* If in playback mode, we scan back */
- mode = 1;
- else if ((result != PlayerRecording) &&
- (result != PlayerRecordPause)) /* Otherwise, we rewind - Not valid if recording */
- mode = 0;
- else
- {
- DisplayError("Reverse not valid when recording", " ");
- return (PlayerReturnError);
- }
-
- sprintf(command, "RW%d", mode);
- return (NECSendCode(theObject, command, 0));
- } /* end function NECReverse */
-
-
- int
- NECScanIndex(VideoObject* theObject,
- enum Direction dir)
- {
- int result;
- result = NECQueryStatus(theObject);
- addMode = 0;
-
- if (result != PlayerStop) /* NEC must be in stop mode. */
- NECStop(theObject);
-
- NECSendCode(theObject, "IC", 0);
- if (dir == Forward)
- return (NECSendCode(theObject, "FF0", 0));
- else
- return (NECSendCode(theObject, "RW0", 0));
-
- } /* end function NECScanIndex */
-
-
- int
- NECSearchIndex(VideoObject* theObject,
- int num,
- int dir)
- {
- char command[4];
- int status;
-
- status = NECQueryStatus(theObject);
-
- if (status != PlayerStop)
- NECStop(theObject);
-
- sprintf(command, "IS%d", num);
- NECSendCode(theObject, command, 0);
- if (dir)
- return (NECSendCode(theObject, "RW0", 0));
- else
- return (NECSendCode(theObject, "FF0", 0));
-
- } /* end function NECSearchIndex */
-
- int
- NECWait(VideoObject* theObject,
- char* status)
- {
- char command[15];
-
- sprintf(command, "WN:%s", status);
- return (NECSendCode(theObject, command, 0));
- } /* end function NECWait */
-
-
- int
- NECPower(VideoObject* theObject,
- int mode)
- {
- if (mode == FeatureOn)
- return (NECSendCode(theObject, "PW1", 0));
- else if (mode == FeatureOff)
- return (NECSendCode(theObject, "PW0", 0));
- else /* Toggles */
- return (NECSendCode(theObject, "PW", 0));
- } /* end function NECPower */
-
-
- int
- NECSetAddressingMode(VideoObject* theObject, int mode)
- {
- addMode = mode;
- } /* end function NECSetAddressingMode */
-
-
- int
- NECSetAudio(VideoObject* theObject,
- int mode)
- {
- if (mode)
- NECSendCode(theObject, "AM0", 0);
-
- switch (mode)
- {
- case 0:
- audioMuted = 1;
- return (NECSendCode(theObject, "AM1", 0));
- case 1:
- return (NECSendCode(theObject, "RLL", 0));
- case 2:
- return (NECSendCode(theObject, "RLR", 0));
- case 3:
- return (NECSendCode(theObject, "RLS", 0));
- case 4:
- return (NECSendCode(theObject, "RLN", 0));
- }
-
- } /* end function NECSetAudio */
-
- int
- NECSetVideo(VideoObject* theObject,
- int mode)
- {
- if (mode == FeatureOn) /* On */
- return (NECSendCode(theObject, "VM0", 0));
- else /* Off */
- return (NECSendCode(theObject, "VM1", 0));
- } /* end function NECSetVideo */
-
-
- int
- NECQueryVideo(VideoObject* theObject)
- {
- NECSendCode(theObject, "PT", 1);
- return (NECReadResponse(theObject, "PT"));
- } /* end function NECQueryVideo */
-
-
-
- int
- NECQueryAudio(VideoObject* theObject)
- {
- NECSendCode(theObject, "DS5", 1);
- return (NECReadResponse(theObject, "DS5"));
- } /* end function NECQueryAudio */
-
-
- int
- NECScreenSelect(VideoObject* theObject,
- int color,
- int brightness)
- {
- char code[6];
-
- sprintf(code, "MB%d:%d", color, brightness);
- return (NECSendCode(theObject, code, 0));
- } /* end function NECScreenSelect */
-
-
-
- /* Returns tape address in frames, NOT SECONDS.
- * Valid only when in playback mode.
- */
- int
- NECQueryFrame(VideoObject* theObject)
- {
- int address;
- int result;
-
- result = NECQueryStatus(theObject);
-
- if (result == PlayerForwardPlay)
- {
- NECSendCode(theObject, "RP", 1);
- address = FrameRate * NECReadResponse(theObject, "RP"); /* Put in terms of frames */
- return (address);
- }
- else
- {
- DisplayError("Player must be in playback mode first", " ");
- return PlayerReturnError;
- }
- } /* end function NECQueryFrame */
-
-
- int
- NECClearScreen(VideoObject* theObject)
- {
- return (NECSendCode(theObject, "ELA",0));
- } /* end function NECClearScreen */
-
-
-
- /* This function returns all speeds in terms of 30 frame-per-second
- * devices, even though the internal calculations are done in
- * rate-independent units.
- */
-
- int
- NECCalcSpeed(VideoObject* theObject,
- int framesInEdit,
- int playMode)
- {
- if (framesInEdit > FrameRate * 2) /* Don't go into high speed unless requested frame... */
- { /* ...rate is greater than 2x speed (arbitrary heuristic) */
- if (framesInEdit <= (5 * FrameRate))
- framesInEdit = 150; /* 5x speed (for SP mode) */
- else if (framesInEdit <= (9 * FrameRate))
- framesInEdit = 270; /* 9x speed (for SP mode, fastest speed available) */
- }
- else
- if (framesInEdit < (FrameRate / 10))
- framesInEdit = 1; /* 1/30th speed */
- else if (framesInEdit < (FrameRate / 5))
- framesInEdit = 3; /* 1/10th speed */
- else if (framesInEdit < FrameRate)
- framesInEdit = 6; /* 1/5th speed */
- else
- framesInEdit = 30; /* 1x speed */
-
- return framesInEdit;
- } /* end function NECCalcSpeed */
-
-
-
- int
- NECPlayAtSpeedDir(VideoObject* theObject,
- int framesPerSecond,
- enum Direction direction)
- {
- int speed;
- static int status = PlayerForwardPlay;
- static int lastSpeed = 0;
-
- if ((status == PlayerRecording) || (status == PlayerRecordPause)) /* Error checks */
- {
- DisplayError("Player cannot change speed when recording", " ");
- return PlayerReturnError;
- }
- else if (status == PlayerStop)
- {
- DisplayError("Player cannot change speed when in stop mode", " ");
- return PlayerReturnError;
- }
- speed = NECCalcSpeed(theObject, framesPerSecond, 0);
- if (speed == lastSpeed) /* Was a different speed requested? */
- return (PlayerOk); /* No, don't bother sending a new command to the player */
-
- lastSpeed = speed; /* Update new speed requested */
- switch (speed)
- {
- case 1: /* 1/30th speed */
- if (direction == Forward) /* NEC PC-VCR doesn't allow reverse playback at slow speeds */
- {
- switch (status) /* Do the right thing according to player's current speed */
- {
- case PlayerPause: /* Paused, increase speed one notch */
- NECSendCode(theObject, "SL+", 0);
- break;
- case NECSlow1_30: /* Already at requested speed; do nothing */
- break;
- case NECSlow1_10: /* Go into next slower speed */
- NECSendCode(theObject, "SL-", 0);
- break;
- case NECSlow1_5: /* Slow speed two notches */
- NECSendCode(theObject, "SL-", 0);
- NECSendCode(theObject, "SL-", 0);
- break;
- case NECPictureSearch:
- case NECRPictureSearch:
- case NECHiSpeedSearch:
- case NECRHiSpeedSearch:
- NECSendCode(theObject, "PL", 0); /* Put into play mode first */
- case PlayerForwardPlay:
- NECSendCode(theObject, "SL-", 0);
- NECSendCode(theObject, "SL-", 0);
- NECSendCode(theObject, "SL-", 0);
- break;
- } /* end switch (status) */
- status = NECSlow1_30;
- } /* end if (direction... */
- break; /* end 1/30th speed */
- case 3: /* 1/10th speed */
- if (direction == Forward) /* NEC PC-VCR doesn't allow reverse playback at slow speeds */
- {
- switch (status) /* Do the right thing according to player's current speed */
- {
- case PlayerPause: /* Paused, increase speed two notches */
- NECSendCode(theObject, "SL+", 0);
- NECSendCode(theObject, "SL+", 0);
- break;
- case NECSlow1_30: /* Increase speed one notch */
- NECSendCode(theObject, "SL+", 0);
- break;
- case NECSlow1_10: /* Already at requested speed; do nothing */
- break;
- case NECSlow1_5: /* Slow speed one notch */
- NECSendCode(theObject, "SL-", 0);
- break;
- case NECPictureSearch:
- case NECRPictureSearch:
- case NECHiSpeedSearch:
- case NECRHiSpeedSearch:
- NECSendCode(theObject, "PL", 0); /* Put into play mode first */
- case PlayerForwardPlay:
- NECSendCode(theObject, "SL-", 0);
- NECSendCode(theObject, "SL-", 0);
- break;
- } /* end switch (status) */
- status = NECSlow1_10;
- } /* end if (direction... */
- break;
- case 6: /* 1/5th speed */
- if (direction == Forward) /* NEC PC-VCR doesn't allow reverse playback at slow speeds */
- {
- switch (status) /* Do the right thing according to player's current speed */
- {
- case PlayerPause: /* Paused, increase speed three notches */
- NECSendCode(theObject, "SL+", 0);
- NECSendCode(theObject, "SL+", 0);
- NECSendCode(theObject, "SL+", 0);
- break;
- case NECSlow1_30: /* Increase speed two notches */
- NECSendCode(theObject, "SL+", 0);
- NECSendCode(theObject, "SL+", 0);
- break;
- case NECSlow1_10: /* Go into next higher speed */
- NECSendCode(theObject, "SL+", 0);
- break;
- case NECSlow1_5: /* Already at requested speed; do nothing */
- break;
- case NECPictureSearch:
- case NECRPictureSearch:
- case NECHiSpeedSearch:
- case NECRHiSpeedSearch:
- NECSendCode(theObject, "PL", 0); /* Put into play mode first */
- case PlayerForwardPlay:
- NECSendCode(theObject, "SL-", 0);
- break;
- } /* end switch (status) */
- status = NECSlow1_5;
- } /* end if (direction... */
- break;
- case 30: /* 1x speed */
- if (direction == Forward) /* NEC PC-VCR doesn't support reverse play at normal speed */
- {
- NECSendCode(theObject, "PL", 0);
- status = PlayerForwardPlay;
- }
- break;
- case 150: /* Fast speed (5x SP mode, 9x EP mode) */
- if (direction == Forward)
- {
- NECSendCode(theObject, "FF1", 0);
- status = NECPictureSearch;
- }
- else
- {
- NECSendCode(theObject, "RW1", 0);
- status = NECRPictureSearch;
- }
- break;
- case 270: /* Jet speed (9x SP mode, 21x EP mode) */
- if (direction == Forward)
- {
- NECSendCode(theObject, "FF2", 0);
- status = NECHiSpeedSearch;
- }
- else
- {
- NECSendCode(theObject, "RW2", 0);
- status = NECRHiSpeedSearch;
- }
- break;
- } /* end switch (speed) */
- return PlayerOk;
- } /* end function NECPlayAtSpeedDir */
-
-
- int NECRecord(VideoObject* theObject)
- {
- return(NECSendCode(theObject, "RC", 0));
- } /* end function NECRecord */
-
-
- int NECRecordFromTo(VideoObject* theObject,
- int startAddress,
- int endAddress,
- int speed)
- {
- int end;
- int endFrame;
- char command[10];
-
- if ((startAddress == 0) && (endAddress == 0)) /* Enter insert edit mode */
- return(NECSendCode(theObject, "PI", 0));
- else if ((startAddress == 0) && (endAddress > 0)) /* Record from present address until end address is reached */
- {
- end = endAddress / FrameRate;
- endFrame = endAddress % FrameRate;
- sprintf(command, "SP%d:%d", end, endFrame);
- return(NECSendCode(theObject, command, 0));
- }
- } /* end function NECRecordFromTo */
-
-
- int
- NECPing(VideoObject* theObject)
- {
- int nr;
- char response[1];
-
- write(theObject->DevConfig->fd, "PW1\r", 4); /* Power on command */
- sprintf(diagMsg, "%s :\tSent ping.\n",
- theObject->DevConfig->serialPort);
- PrintDiagnostics(diagMsg);
- nr = read(theObject->DevConfig->fd, response, 1); /* Read CP */
- if (nr)
- {
- sprintf(diagMsg, "%s :\tSuccessful ping.\n",
- theObject->DevConfig->serialPort);
- PrintDiagnostics(diagMsg);
- read(theObject->DevConfig->fd, response, 1); /* Read AO */
- }
- else
- {
- sprintf(diagMsg,"%s :\tPing unsuccessful.\n",
- theObject->DevConfig->serialPort);
- PrintDiagnostics(diagMsg);
- }
- return nr;
- } /* end function NECPing */
-
-
- void
- NECErrorDecode(VideoObject* theObject,
- int ecode,
- char* string)
- {
- char errMsg[50];
-
- switch (ecode)
- {
- case ErrPowerOff :
- strcpy(errMsg, "Please turn the VCR power on");
- break;
- case ErrCantReadAdd :
- strcpy(errMsg, "Tape address cannot be read");
- break;
- case ErrNoCassette:
- strcpy(errMsg, "Please insert a cassette into VCR first");
- break;
- case ErrIncorrectCommand :
- strcpy(errMsg, "Incorrect command");
- break;
- case ErrIncorrectParameter :
- strcpy(errMsg, "Incorrect parameter(s) or no parameters needed");
- break;
- case ErrReceptionBuffOverflow :
- strcpy(errMsg, "Warning : there are too many commands in the buffer");
- break;
- case ErrCantReadHeader :
- strcpy(errMsg, "Header cannot be read");
- break;
- case ErrCantExecCommand :
- sprintf(errMsg, "%s cannot be executed. Please check VCR mode", string);
- break;
- } /* end switch */
- DisplayError(errMsg, " ");
- return;
- } /* end function NECErrorDecode */
-